from basic import *
from tool import *
from util import *


# 初始化
# 输入一个列表，如['a','b','c']
# 输出一个把每个元素都封装为列表的列表，如[['a'],['b'],['c']]
def ini(sample_list):
    C = []
    for x in sample_list:
        C.append([x])
    return C

# 查找最小距离的一对列表
# 输入初始化以后的列表，如[['a'],['b'],['c']]
# 输出类间距离最短的两个元素的下标列表，如[0,1]
def find_min(C):
    # 逻辑告诉我们无论怎样做都必须两两之间的全部距离，这里用一个二维列表来记录
    # 数学告诉我们a->b与b->a的距离是一样的，其实开销可以减小一半
    # Laziness tells me math said bullshit
    scale = len(C)
    d = [[0 for i in range(scale)] for i in range(scale)]
    min_d = internal_classes(C[0], C[1])
    where_min_d = [0, 1]
    for i in range(scale):
        for j in range(scale):
            d[i][j] = internal_classes(C[i], C[j])
            if i != j and d[i][j] < min_d:
                min_d = d[i][j]
                where_min_d = [i, j]
    return where_min_d

# C:=C-Ci-Cj+CiUCj
# 输入全集列表C及其选出的两个子列表Ci、Cj，如C=[['a'],['b'],['c']]，Ci=['a'], Cj=['b']
# 需要注意的是，逻辑上，集合Ci与集合Cj是集合C的【元素】，而交并差都是【集合】之间的运算
# 输出合并Ci与Cj之后的全集列表，如[[['a'],['b']],['c']]
def merge(C, i, j):
    # 在数学上，集合[[1],[2]]与集合[[1,2]]的并集有三个元素，因为[1],[2],[1,2]都是完全不同的元素。但在这里的逻辑上，需要结果为[[1,2]]，所以另外定义了特殊的“交集”运算
    # 交集与差集的运算是针对集合的（如[[1]]）而非元素（如[1])，所以需要手动装进列表再传参。（其实已经特殊处理的交集运算无必要这样做，但为了逻辑一致遵守了统一的写法）
    C_u = special_union([C[i]], [C[j]])
    C_d = difference(difference(C, [C[i]]), [C[j]])
    C_n = C_d
    C_n.append(C_u)
    return C_n

# 查找规模最大的一个子列表
# 输入全集C，如[[['a'],['b']],['c']]
# 输出规模最大即集合内元素最多的列表的下标，如0
def find_largest(C):
    s = [0] * len(C)
    max_s = len(C[0])
    where_max_s = 0
    for x in range(len(C)):
        s[x] = len(C[x])
        if s[x] > max_s:
            max_s = s[x]
            where_max_s = x
    return where_max_s

# 主流程
# 输入样本列表，如['a','b','c']
# 输出层次分类结果，如[[['a'],['b']],[['c']]]
def process(sample_list):
    C = ini(sample_list)
    # This infinite loop is to simulate the do-while syntax in Python
    while True:
        where_min_d = find_min(C)
        i, j = where_min_d
        C = merge(C, i, j)
        where_max_s = find_largest(C)
        if count_elem(C[where_max_s]) > 0.5 * len(C):
            break
    CM = C[where_max_s]
    CN = difference(C, [CM])
    return [CM, CN]
def deList(List):
    temp = []
    if isinstance(List,list):
        for x in List:
            if isinstance(x,list):
                temp = temp + deList(x)
            else:
                temp.append(x)
        return temp
    else:
        return temp

if __name__ == '__main__':
    # a = ['2333333333', '天若有情天亦老', '3.14159',
    #      'YvesX', '4444', 'To be or not to be']
    # b = ['阿里巴巴', '阿童木', '阿里爷爷', '阿凡提', '阿里里里']  # 请不要笑
    # c = ['常温', '蔬菜', '加热', '水果']  # 请不要笑
    # print("Input:")
    # print(a)
    # print("Output:")
    # res = process(a)
    # print(res[0])
    # print(res[1])
    import sys
    sys.path.append('C:\\Users\\LENOVO\\Desktop\\machineLearning\\Code\\version1.1')
    from dataAccess import getData
    import random
    goodSamples = getData.getGood("normalparams","pwd")[0:50]
    badSamples = getData.getBad()[0:10]
    samples = goodSamples + badSamples
    random.shuffle(samples)
    print(1)
    rst = process(samples)
    rst[0] = deList(rst[0])
    rst[1] = deList(rst[1])
    print("0",rst[0])
    print("1",rst[1])
    rst1 = process(rst[1])
    rst1[0] = deList(rst1[0])
    rst1[1] = deList(rst1[1])
    print("1:0",rst1[0])
    print("1:1",rst1[1])
    rst11 = process(rst1[1])
    rst11[0] = deList(rst11[0])
    rst11[1] = deList(rst11[1])
    print("1:0:0",rst11[0])
    print("1:1:1",rst11[1])
